/*
 * readGenerator.cc
 *
 *  Created on: Aug 12, 2013
 *      Author: hxin
 */

#include "SeedTree.h"
#include "HashTable.h"
#include "LongHashTable.h"
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <cassert>

using namespace std;

int main(int argc, char* argv[]) {
	if (argc != 8 && argc != 6 && argc != 5) {
		cerr
				<< "usage: $>mapSimulator refFile hashFile -h readFile chromoNum threshold maxLength"
				<< endl
				<< "usage: $>mapSimulator refFile hashFile -o readFile chromoNum"
				<< endl << "usage: $> mapSimulator refFile hashFile -l readFile"
				<< endl;
	}

	string temp;
	string read;

	ifstream readFile(argv[4]);
	if (!readFile.is_open()) {
		cerr << "Failed to open readFile " << endl;
		exit(1);
	}

//discard location
	readFile >> temp;
//get read
	readFile >> read;

	string longSeed;

	vector<int> seedNum;
	vector<long int> locCompo;
	vector<int> BSCompo;
	vector<int> linearED;

	int seedLen;
	int maxLen;

	switch ((char) argv[3][1]) {

	case 'h':
	{
		SeedTree tree;

		if (argc != 8) {
			cerr << "Wrong arguments!!" << endl;
			exit(1);
		}

		//Getting LengthCompo

		tree.loadFiles(argv[2], argv[1]);
		tree.loadChromo(atoi(argv[5]));

		maxLen = atoi(argv[7]);
		tree.genTree(atoi(argv[6]), maxLen + 1);

		seedNum.resize((read.length() + 1) / tree.getRootSeedLength() + 1, 0);

		while (readFile.good()) {
			int seedPos = 0;
			int effectiveLen = 0;
			int curSeedNum = -1;
			do {
				longSeed = read.substr(seedPos, maxLen);
				curSeedNum++;
				effectiveLen = tree.getEffectiveLen(longSeed);
				seedPos += effectiveLen;
			} while (effectiveLen > 0);
//		tree.getEffectiveLen(longSeed)

			seedNum[curSeedNum]++;
			readFile >> temp;
			readFile >> read;
		}

		//Getting LocCompo:

		readFile.clear();
		readFile.seekg(0);

		locCompo.resize((read.length() + 1) / tree.getRootSeedLength() + 1, 0);
		BSCompo.resize((read.length() + 1) / tree.getRootSeedLength() + 1, 0);
		linearED.resize((read.length() + 1) / tree.getRootSeedLength() + 1, 0);

		readFile >> temp;
		readFile >> read;

		while (readFile.good()) {
			int seedPos = 0;
			int effectiveLen = 0;
			int curSeedNum = 0;
			int tempLocLen = 0;
			int tempBS = 0;
			int tempLinear = 0;

			//When jigsaw seeds works
			do {
				longSeed = read.substr(seedPos, maxLen);
				curSeedNum++;
				HetAnaData seedData = tree.getHetAnaData(longSeed);
				effectiveLen = seedData.effectiveSeedLen;
				tempLocLen += seedData.locationLen;

				if (effectiveLen > tree.getRootSeedLength())
					assert(seedData.extEntryNum > 0);

				tempBS += 31 - __builtin_clz(seedData.extEntryNum);
				//This is in case the last seed is too long
				if (seedData.locationLen >= 0) {
					locCompo[curSeedNum] += tempLocLen;
					BSCompo[curSeedNum] += tempBS;
				}
				seedPos += effectiveLen;
			} while (effectiveLen > 0);

			//When jigsaw seeds does not work
			while (curSeedNum < locCompo.size()) {
				tempLocLen = 0;
				tempBS = 0;
				tempLinear = 0;
				int seedLen = read.length() / curSeedNum;

				for (int i = 0; i < curSeedNum; i++) {
					longSeed = read.substr(i * seedLen,
							seedLen + tree.getRootSeedLength());
					HetAnaData seedData = tree.getHetAnaData(longSeed);
					tempLocLen += seedData.locationLen;
					effectiveLen = seedData.effectiveSeedLen;

					assert(effectiveLen >= tree.getRootSeedLength());
					//If we have overlapping seeds, we have to do linear search
					if (effectiveLen > seedLen) {
						assert(seedData.extEntryNum > 0);
						linearED[curSeedNum] += seedData.extEntryNum;
					} else
						tempBS += 31 - __builtin_clz(seedData.extEntryNum);
				}
				locCompo[curSeedNum] += tempLocLen;
				BSCompo[curSeedNum] += tempBS;

				curSeedNum++;
			}

			seedNum[curSeedNum]++;
			readFile >> temp;
			readFile >> read;
		}

		//Print data:
		for (int i = 1; i < seedNum.size(); i++) {
			cout << seedNum[i] << " reads have " << i << " seeds" << endl;
		}

		for (int i = 1; i < seedNum.size(); i++) {
			cout << "When error is " << i << ", there are:" << endl;
			cout << locCompo[i] << " locations to verify" << endl;
			cout << BSCompo[i] << " binary searches" << endl;
			cout << linearED[i] << " linear edit distance" << endl;
		}
	}
		break;

	case 'o': {
		if (argc != 6) {
			cerr << "Wrong arguments" << endl;
			exit(1);
		}
		HashTable ht;

		ht.loadHash(argv[2]);
		ht.loadChromo(atoi(argv[5]));

		seedLen = ht.getSeedLength();

		locCompo.resize((read.length() + 1) / seedLen + 1, 0);

		while (readFile.good()) {
			int seedPos = 0;
			int tempLocNum = 0;

			for (int i = 1; i < locCompo.size(); i++) {
				string seed = read.substr(seedLen * (i - 1), seedLen);
				tempLocNum += ht.getLocLength(seed);
				locCompo[i] += tempLocNum;
			}

			readFile >> temp;
			readFile >> read;
		}

		for (int i = 1; i < locCompo.size(); i++) {
			cout << "When error is: " << i << " there are:" << endl;
			cout << locCompo[i] << " locations to verify" << endl;
		}
	}
		break;

	case 'l': {
		if (argc != 5) {
			cerr << "Wrong arguments!!" << endl;
			exit(1);
		}

		LongHashTable longht;

		longht.loadHash(argv[2]);

		seedLen = longht.getSeedLength();

		locCompo.resize((read.length() + 1) / seedLen + 1, 0);

		while (readFile.good()) {
//			cout << read << endl;
			int seedPos = 0;
			int tempLocNum = 0;

			for (int i = 1; i < locCompo.size(); i++) {
				string seed = read.substr(seedLen * (i - 1), seedLen);
				tempLocNum += longht.getLocLength(seed);
				locCompo[i] += tempLocNum;
			}

			readFile >> temp;
			readFile >> read;
		}

		for (int i = 1; i < locCompo.size(); i++) {
			cout << "When error is: " << i << " there are:" << endl;
			cout << locCompo[i] << " locations to verify" << endl;
		}
	}
		break;

	default:
		cout << "Nothing executed " << endl;
		break;

	}

	readFile.close();

}
